package com.lagou.edu.factory;

import com.lagou.edu.annotationt.Autowried;
import com.lagou.edu.annotationt.Service;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.reflections.Reflections;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author 应癫
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    /**
     * xml配置bean做法
     * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    /**
     * 注解配置bean的做法
     * 1.找到含有注解@service的类，通过反射技术实例化对象并且存储待用（map集合）
     * 2.对外提供获取实例对象的接口
     */

    private static Map<String,Object> map = new HashMap<>();  // 存储对象

    static {
        //获取包com.lagou.edu下面的所有的Java文件
        Reflections reflections = new Reflections("com.lagou.edu");
        //找出带有service注解的class
        Set<Class<?>> containServiceClass = reflections.getTypesAnnotatedWith(Service.class);
        containServiceClass.stream().forEach(beanServiceClass->{
            try {
                //将class实例化成对象
                Object obj = beanServiceClass.newInstance();
                //获取该类的注解信息
                Service serviceAnnotation = beanServiceClass.getAnnotation(Service.class);
                //获取注解值（注解括号的值，别名）
                String annotationValue = serviceAnnotation.value();
                //如果么有别名，取类名
                if(annotationValue==null || "".equals(annotationValue)){
                    String simpleName = beanServiceClass.getSimpleName();
                    //如果是接口实现类,即该类是实现接口的，比如TransferServiceImpl实现接口TransferService
                    Class<?>[] interfaces = beanServiceClass.getInterfaces();
                    if(interfaces!=null && interfaces.length>0){
                        simpleName = interfaces[0].getSimpleName();
                    }
                    //驼峰命名法，首字母小写
                    annotationValue = (new StringBuilder()).append(Character.toLowerCase(simpleName.charAt(0))).append(simpleName.substring(1)).toString();
                    /************将驼峰命名法的类名+该类的实例，以键值对的形式放到map中，备用*********/
                    System.out.println("开始加载对象名称:"+annotationValue+",值："+obj);
                    map.put(annotationValue,obj);
                    /************将驼峰命名法的类名+该类的实例，以键值对的形式放到map中，备用*********/
                }
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });
        //通过反射获取map中实例的属性信息:找到带有注解@Autowired
        if(!map.isEmpty()){
            for(Map.Entry<String,Object> entry:map.entrySet()){
                Object obj = entry.getValue();
                String key = entry.getKey();
                //获取该对象的class信息
                Class<?> clazz = obj.getClass();
                //通过反射，找到这个类的自己的全部属性（注意：父类的属性这里取不到）
                Field[] fields = clazz.getDeclaredFields();
                for(int i=0;i<fields.length;i++){
                    Field field = fields[i];
                    //判断该属性是否使用了注解@Autowired
                    if(field.isAnnotationPresent(Autowried.class)){
                        //设置访问权限
                        field.setAccessible(true);
                        //在map容器中找到属性的对象-一定存在，否则报错。注意：标注@Autowird的注解属性，这个类会加@Service或者@Mapper等等注解。
                        Object value = map.get(field.getName());
                        //为属性赋值
                        try {
                            System.out.println("对象名称:"+key+"，开始加载装配对象,名称:"+field.getName()+",值:"+value);
                            field.set(obj,value);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    //通过类名的获取该对象（默认首字母小写）
    public static Object getBean(String name){
        Object o = map.get(name);
        return o;
    }

}
